package xj.graph2d;

import static xj.graph2d.DrawShapeConstants.CLONE_PROTOTYPE_DRAW_ATTR;
import static xj.graph2d.DrawShapeConstants.CLONE_SYSTEM_DRAW_ATTR;
import static xj.graph2d.DrawShapeConstants.USE_PROTOTYPE_DRAW_ATTR;
import static xj.graph2d.DrawShapeConstants.USE_SYSTEM_DRAW_ATTR;

import java.util.HashMap;
import java.util.Map;

import javax.swing.Icon;

public class DrawShapeFactory { 

  public DrawShapeBase makeShape(String name) {
    return makeShape(name, true);
  }

  public DrawShapeBase makeShape(String name, boolean deepClone) {
    if (name != null) {
      Object o = protoMap.get(name);
      if (o instanceof DrawShapeBase) {
	try { 
	  DrawShapeBase shape;
	  //shape = (DrawShapeBase) ((DrawShapeBase) o).clone();
	  shape = (DrawShapeBase) ((DrawShapeBase) o).cloneDrawShape(deepClone);
	  return shape;
	} catch (CloneNotSupportedException e) {
	  e.printStackTrace();
	  return null;
	}
      }
    }
    return null;
  }

  public DrawShapeBase getPrototype(String name) {
    if (name != null) {
      return protoMap.get(name);
    }
    return null;
  }

  public void addPrototype(String name, DrawShape shape) {
    if (name != null && shape instanceof DrawShapeBase) {
      protoMap.put(name, (DrawShapeBase) shape);
    }
  }

  public static DrawShapeBase cloneDrawShape(DrawShape proto,
					     SimpleDrawView view, int attrMode) {
    return cloneDrawShape(proto, view, attrMode, true); 
  }

  public static DrawShapeBase cloneDrawShape(DrawShape proto,
					     SimpleDrawView view, 
					     int attrMode, 
					     boolean deepClone) {
    DrawShapeBase shape = null;
    if (proto != null) {
      try { 
	//shape = (DrawShapeBase) proto.clone();
	shape = (DrawShapeBase) proto.cloneDrawShape(deepClone);
	cloneDrawAttr(proto, shape, view, attrMode);
      } catch (CloneNotSupportedException e) {
	e.printStackTrace();
	return null;
      }
    }
    return shape;
  }

  public static void cloneDrawAttr(DrawShape proto, DrawShape shape,
				   SimpleDrawView view, int attrMode) {
    if (proto != null && shape != null) {
      DrawAttr attr = null;
      boolean isOpenShape = (proto instanceof OpenShape);
      ArrowAttr headArrowAttr = null;
      ArrowAttr tailArrowAttr = null;
      switch (attrMode) {
      case USE_SYSTEM_DRAW_ATTR:
      case CLONE_SYSTEM_DRAW_ATTR:
	if (view != null) {
	  attr = view.getDrawAttr();
	  if (isOpenShape) {
	    headArrowAttr = view.getHeadArrowAttr();
	    tailArrowAttr = view.getTailArrowAttr();
	  }
	  if (attrMode == CLONE_SYSTEM_DRAW_ATTR) {
	    if (attr != null) {
	      attr = (DrawAttr) attr.clone();
	    } else {
	      attr = new DrawAttr();
	    }
	  }
	}
	break;

      case USE_PROTOTYPE_DRAW_ATTR:
      case CLONE_PROTOTYPE_DRAW_ATTR:
	attr = proto.getDrawAttr();
	if (isOpenShape) {
	  OpenShape oproto = (OpenShape) proto;
	  headArrowAttr = oproto.getHeadArrow();
	  tailArrowAttr = oproto.getTailArrow();
	}
	if (attrMode == CLONE_PROTOTYPE_DRAW_ATTR) {
	  if (attr != null) {
	    attr = (DrawAttr) attr.clone();
	  } else {
	    attr = new DrawAttr();
	  }
	}
	break;
      }

      if (attr != null) {
	shape.setDrawAttr(attr);
      }
      if (isOpenShape && 
	  (headArrowAttr != null || tailArrowAttr != null)) {
	OpenShape oshape = (OpenShape) shape;
	oshape.addArrows(headArrowAttr, tailArrowAttr);
      }
    }
  }

  public Icon getIcon(String name) {
    if (name != null) {
      Object ic = iconMap.get(name);
      if (ic instanceof Icon) {
	return (Icon) ic;
      }
    }
    return null;
  }

  public void setIconMap(Map<String, Icon> iconMap) {
    this.iconMap = iconMap;
  }

  public static DrawShapeFactory getInstance() {
    if (theInstance == null) {
      theInstance = new DrawShapeFactory();
    }
    return theInstance;
  }

  protected DrawShapeFactory() {
    protoMap = new HashMap<String, DrawShapeBase>();
  }

  protected static DrawShapeFactory theInstance = null;

  protected Map<String, DrawShapeBase> protoMap;

  protected Map<String, Icon> iconMap;

}
